package com.modular.filter;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.modular.config.TokenConfig;
import com.modular.constant.BaseCodeDesc;
import com.modular.exception.ModularException;
import com.modular.json.JackJsonUtil;
import com.modular.result.CodeDescUtils;
import com.modular.result.RspMessage;
import com.modular.security.JwtTokenService;
import com.modular.utils.SecurityUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;

/**
 * 第一个过滤器负责检查是否有token
 */
@Order(1)
@Component
public class TokenFilter extends OncePerRequestFilter {
    private Logger logger = LoggerFactory.getLogger(TokenFilter.class);
    @Autowired
    private TokenConfig tokenConfig;
    @Autowired
    private JwtTokenService tokenService;
    private AntPathMatcher pathMatcher = new AntPathMatcher();


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            String path = request.getRequestURI();
            logger.info("TokenFilter path {}",path);
            if (checkIgnorePath(path)) {
                chain.doFilter(request, response);
                return;
            }
            String token = getToken(request);
            logger.info("TokenFilter path {} token {}",path,token);
            if (StrUtil.isEmpty(token)) {
                throw new ModularException(BaseCodeDesc.TOKEN_UNDEFIND);
            }
             SecurityUtil.setSecurityContextAuthentication(tokenService.getTokenPrincipalToCache(token));
            chain.doFilter(request, response);
        }catch (Exception e){
            logger.error("TokenFilter err",e);
            responseUnauthorized(response,e);
        }
        finally {
            SecurityContextHolder.clearContext();
        }

    }

    /**
     * 获得token信息
     * @param request
     * @return
     */
    private String getToken(HttpServletRequest request){
        if(CollUtil.isEmpty(tokenConfig.getTokenList())){
            throw new ModularException(BaseCodeDesc.TOKEN_UN_CONFIG);
        }
        String token = null;
        for(String tokenSign: tokenConfig.getTokenList()){
            token = getToken(request,tokenSign);
            if(StrUtil.isNotEmpty(token)){
                return token;
            }
        }
        return StrUtil.EMPTY;
    }

    /**
     * 从request中获得token数据
     * @param request
     * @param tokenSign
     * @return
     */
    private String getToken(HttpServletRequest request,String tokenSign){

        String token = request.getParameter(tokenSign);
        if(StrUtil.isEmpty(token)){
            token  = request.getHeader(tokenSign);
        }
        return token;
    }

    /**
     * 判断路径是否在忽略的列表中
     * @param path
     * @return
     */
    private boolean checkIgnorePath(String path){
        if(CollUtil.isEmpty(tokenConfig.getIgnorePaths())){
            return Boolean.FALSE;
        }
        return pathPatternMatcher(tokenConfig.getIgnorePaths(),path);
    }

    /**
     * 对比路径
     * @param pathPatterns
     * @param path
     * @return
     */
    private boolean pathPatternMatcher(Collection<String> pathPatterns, String path) {
        return pathPatterns.stream().anyMatch((pattern) -> {
            return this.pathMatcher.matchStart(pattern, path);
        });
    }

    private void responseUnauthorized(HttpServletResponse response, Exception e) {
        String toJson = null;
        if(ObjectUtil.isNotNull(e)) {
            String err = e.getMessage();
            String code = BaseCodeDesc.DEFATUL_MSG.getCode();
            if(e instanceof ModularException me){
                err = me.getErrMsg();
                code = me.getCode();
            }
            RspMessage<Object> rspMessage = RspMessage.result(code,err,null);

            toJson = JackJsonUtil.toJsonIgnoreNull(rspMessage);
        }
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        response.setStatus(HttpStatus.OK.value());
        PrintWriter writer = null;

        try {
            writer = response.getWriter();
            writer.write(toJson);
            writer.flush();
        } catch (IOException var10) {
            logger.error("io异常");
        } finally {
            if (writer != null) {
                writer.close();
            }

        }

    }
}
